﻿#include "ff.h"
#include "db_format.h"
#include "ffunicode.h"

//	Unicode符号范围(十六进制)	| UTF-8编码方式（二进制）
//	--------------------------------------------------------------------
//	0000 0000-0000 007F			| 0xxxxxxx
//	0000 0080-0000 07FF			| 110xxxxx 10xxxxxx
//	0000 0800-0000 FFFF			| 1110xxxx 10xxxxxx 10xxxxxx
//	0001 0000-0010 FFFF			| 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

#define Unicode2utf8											\
		if(unicodeKey < 0x80)									\
		{														\
			if(j+1 > buf_space)	break;							\
			real_buf[j++] = (uint8_t)unicodeKey;				\
		}														\
		else if(unicodeKey < 0x800)								\
		{														\
			if(j+2 > buf_space)	break;							\
			real_buf[j++] = ((unicodeKey >> 6) & 0x1F) | 0xC0;	\
			real_buf[j++] = ((unicodeKey >> 0) & 0x3F) | 0x80;	\
		}														\
		else if(unicodeKey < 0x10000)							\
		{														\
			if(j+3 > buf_space)	break;							\
			real_buf[j++] = ((unicodeKey >> 12) & 0x0F) | 0xE0;	\
			real_buf[j++] = ((unicodeKey >> 6) & 0x3F) | 0x80;	\
			real_buf[j++] = ((unicodeKey >> 0) & 0x3F) | 0x80;	\
		}														\
		else if(unicodeKey < 0x110000)							\
		{														\
			if(j+4 > buf_space)	break;							\
			real_buf[j++] = ((unicodeKey >> 18) & 0x07) | 0xF0;	\
			real_buf[j++] = ((unicodeKey >> 12) & 0x3F) | 0x80;	\
			real_buf[j++] = ((unicodeKey >> 6) & 0x3F) | 0x80;	\
			real_buf[j++] = ((unicodeKey >> 0) & 0x3F) | 0x80;	\
		}														\
		else													\
		{														\
			assert(0);											\
			return 0;											\
		}														\



int ISO_8859_1_to_utf8(const uint8_t* source_buf, uint32_t source_buf_len, uint8_t* real_buf, uint32_t buf_space)
{
#if(0)
	uint32_t len = strlen((char*)source_buf);
	if(len >= buf_space)
	{
		memcpy(real_buf, source_buf, buf_space);
		return buf_space;
	}
	else
	{
		memcpy(real_buf, source_buf, len);
		return buf_space;
	}
#else
	return db_gb2312_to_utf8(source_buf, source_buf_len, real_buf, buf_space);
#endif
}

int UTF_16LE_to_utf8(const uint8_t* source_buf, uint32_t source_buf_len, uint8_t* real_buf, uint32_t buf_space)
{
	uint32_t i = 0;
	uint32_t j  =0;
	uint32_t unicodeKey = 0;

	//if(source_buf[0] == 0xFE && source_buf[1] == 0xFF)
	{
		i = 2;
	}

	while(i < source_buf_len)
	{
		assert((source_buf[i] & 0xC000) != 0xC000);
		if(source_buf[i] < 0x8000)
		{
			if(i+2 > source_buf_len)	break;
			unicodeKey = source_buf[i++];
			unicodeKey = (source_buf[i++] << 8) +unicodeKey;
		}
		else if(source_buf[i] < 0xE000)
		{
			if(i+4 > source_buf_len)	break;
			unicodeKey = source_buf[i++] & 0x1F;
			unicodeKey = (source_buf[i++] << 5) + unicodeKey;
			unicodeKey = ((source_buf[i++] & 0x3F) << 13) + unicodeKey;
			unicodeKey = (source_buf[i++] << 19) + unicodeKey;
		}
		else
		{
			assert(0);
			return 0;
		}

		Unicode2utf8;
	}

	return j;
}

int UTF_16BE_to_utf8(const uint8_t* source_buf, uint32_t source_buf_len, uint8_t* real_buf, uint32_t buf_space)
{
	uint32_t i = 0;
	uint32_t j  =0;
	uint32_t unicodeKey = 0;

	//if(source_buf[0] == 0xFF && source_buf[1] == 0xFE)
	{
		i = 2;
	}

	while(i < source_buf_len)
	{
		assert((source_buf[i] & 0xC000) != 0xC000);
		if(source_buf[i] < 0x8000)
		{
			if(i+2 > source_buf_len)	break;
			unicodeKey = source_buf[i++];
			unicodeKey = (unicodeKey << 8) + source_buf[i++];
		}
		else if(source_buf[i] < 0xE000)
		{
			if(i+4 > source_buf_len)	break;
			unicodeKey = source_buf[i++] & 0x1F;
			unicodeKey = (unicodeKey << 8) + source_buf[i++];
			unicodeKey = (unicodeKey << 6) + (source_buf[i++] & 0x3F);
			unicodeKey = (unicodeKey << 8) + source_buf[i++];
		}
		else
		{
			assert(0);
			return 0;
		}

		Unicode2utf8;
	}

	return j;
}

int db_gb2312_to_utf8(const uint8_t* source_buf, uint32_t source_buf_len, uint8_t* real_buf, uint32_t buf_space)
{
	uint32_t i = 0;
	uint32_t j = 0;
	uint16_t gbKey = 0;
	uint32_t unicodeKey = 0;

	for(;;)
	{
		if(source_buf[i] < 0x80)
		{
			if(i+1 > source_buf_len)	break;
			unicodeKey = source_buf[i++];
		}
		else
		{
			if(i+2 > source_buf_len)	break;
			gbKey = source_buf[i++];
			gbKey = (gbKey << 8) + source_buf[i++];

			unicodeKey = ff_covert_oem2uni(gbKey, 936);
			if(unicodeKey == 0)
			{
				//查找失败用字符‘■’替代，内码是GB（A1,F6）==Unicode（0x25A0）==UTF8（E2,96,A0）
				unicodeKey = 0x000025A0;
			}
			//assert(unicodeKey >= 0x00000800 && unicodeKey <= 0x0000FFFF);
		}

		Unicode2utf8;
	}

	return j;
}

int db_gb2312_to_utf8Ex(const uint8_t* source_buf, uint32_t source_buf_len, uint8_t* real_buf, uint32_t buf_space, int * full)
{
	uint32_t i = 0;
	uint32_t j = 0;
	uint16_t gbKey = 0;
	uint32_t unicodeKey = 0;

	*full = 1;
	for(;;)
	{
		if(source_buf[i] < 0x80)
		{
			if(i+1 > source_buf_len)
			{
				*full = 0;
				break;
			}

			unicodeKey = source_buf[i++];
		}
		else
		{
			if(i+2 > source_buf_len)
			{
				*full = 0;
				break;
			}

			gbKey = source_buf[i++];
			gbKey = (gbKey << 8) + source_buf[i++];

			unicodeKey = ff_covert_oem2uni(gbKey, 936);
			if(unicodeKey == 0)
			{
				//查找失败用字符‘■’替代，内码是GB（A1,F6）==Unicode（0x25A0）==UTF8（E2,96,A0）
				unicodeKey = 0x000025A0;
			}
			//assert(unicodeKey >= 0x00000800 && unicodeKey <= 0x0000FFFF);
		}

		Unicode2utf8;
	}

	return j;
}

int is_gb2312_format(const uint8_t * buf, uint32_t len)
{
	//gb2312编码范围A1A1－F7FE；区位码：高端是区：0xA1-0xF7，低端是位：0xA1-0xFE，其中有5个空位是D7FA-D7FE。
	int ret_format = ASCII_FORMAT;
	uint32_t i=0;
	while(i<len)
	{
		if(buf[i] < 0x80)//ASCII字符
		{
			i += 1;
			ret_format |= ASCII_FORMAT;
		}
		else
		{
			uint8_t Hi = buf[i];
			uint8_t Lo = buf[i+1];
			
			if(Hi < 0xA1 || Hi > 0xF7)
				return ERROR_FORMAT;
			else if(Lo < 0 || Lo > 0xFE)
				return ERROR_FORMAT;
			else if(Hi == 0xD7 && (Lo > 0xFB))
				return ERROR_FORMAT;

			ret_format |= ANSI_FORMAT;
			i += 2;
		}
	}

	return ret_format;
}

int is_utf8_format(const uint8_t * buf, uint32_t len)
{
	//无BOM判断。仅区分 UTF_8_NOBOM_FORMAT 和 ANSI_FORMAT,
	//规则：按照UTF-8规则扫描buf，与错返回ANSI_FORMAT
	//	UTF-8编码方式（二进制）
	//	---------------------------------------------
	//	0xxxxxxx
	//	110xxxxx 10xxxxxx
	//	1110xxxx 10xxxxxx 10xxxxxx
	//	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
	//	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
	//	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

	int ret_format = ASCII_FORMAT;
	uint32_t i=0;
	while(i<len)
	{
		if(buf[i] < 0x80)//ASCII字符
		{
			i += 1;
			ret_format |= ASCII_FORMAT;
		}
		else if((buf[i] & 0xC0) == 0x80)
		{
			if(i+2 >= len)break;
			i += 2;
			ret_format |= ANSI_FORMAT;
		}
		else if((buf[i] & 0xE0) == 0xC0)//	110xxxxx 10xxxxxx
		{
			if(i+2 >= len)break;
			if((buf[i+1] & 0xC0) != 0x80)
			{
				return ERROR_FORMAT;
			}
			ret_format |= UTF_8_NOBOM_FORMAT;
			i += 2;
		}
		else if((buf[i] & 0xF0) == 0xE0)//	1110xxxx 10xxxxxx 10xxxxxx
		{
			if(i+3 >= len)break;
			if( (buf[i+1] & 0xC0) != 0x80 ||
				(buf[i+2] & 0xC0) != 0x80 )
			{
				return ERROR_FORMAT;
			}
			ret_format |= UTF_8_NOBOM_FORMAT;
			i += 3;
		}
		else if((buf[i] & 0xF8) == 0xF0)//	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
		{
			if(i+4 >= len)break;
			if( (buf[i+1] & 0xC0) != 0x80 ||
				(buf[i+2] & 0xC0) != 0x80 ||
				(buf[i+3] & 0xC0) != 0x80 )
			{
				return ERROR_FORMAT;
			}
			ret_format |= UTF_8_NOBOM_FORMAT;
			i += 4;
		}
		else if((buf[i] & 0xFC) == 0xF8)//	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
		{
			if(i+5 >= len)break;
			if( (buf[i+1] & 0xC0) != 0x80 ||
				(buf[i+2] & 0xC0) != 0x80 ||
				(buf[i+3] & 0xC0) != 0x80 ||
				(buf[i+4] & 0xC0) != 0x80 )
			{
				return ERROR_FORMAT;
			}
			ret_format |= UTF_8_NOBOM_FORMAT;
			i += 5;
		}
		else if((buf[i] & 0xFC) == 0xF8)//	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
		{
			if(i+6 >= len)break;
			if( (buf[i+1] & 0xC0) != 0x80 ||
				(buf[i+2] & 0xC0) != 0x80 ||
				(buf[i+3] & 0xC0) != 0x80 ||
				(buf[i+4] & 0xC0) != 0x80 ||
				(buf[i+5] & 0xC0) != 0x80 )
			{
				return ERROR_FORMAT;
			}
			ret_format |= UTF_8_NOBOM_FORMAT;
			i += 6;
		}
		else
		{
			return ERROR_FORMAT;
		}
	}

	return ret_format;
}

int db_check_format_no_bom(const uint8_t * buf, uint32_t len)
{
	//无BOM判断。仅区分 UTF_8_NOBOM_FORMAT 和 ANSI_FORMAT,
	//规则：按照UTF-8规则扫描buf，与错返回ANSI_FORMAT
	//	UTF-8编码方式（二进制）
	//	---------------------------------------------
	//	0xxxxxxx
	//	110xxxxx 10xxxxxx
	//	1110xxxx 10xxxxxx 10xxxxxx
	//	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
	//	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
	//	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

	int ret_format = ASCII_FORMAT;
	uint32_t i=0;
	while(i<len)
	{
		if(buf[i] < 0x80)//ASCII字符
		{
			i += 1;
			ret_format |= ASCII_FORMAT;
		}
		else if((buf[i] & 0xC0) == 0x80)
		{
			i += 2;
			ret_format |= ANSI_FORMAT;
		}
		else if((buf[i] & 0xE0) == 0xC0)//	110xxxxx 10xxxxxx
		{
			if((buf[i+1] & 0xC0) == 0x80)
			{
				i += 2;
				//ret_format |= UTF_8_NOBOM_FORMAT;	//为什么解析到2字节的UTF-8，结果是错的？测试字符串“为什么.mp3”
				ret_format |= ANSI_FORMAT;
			}
			else
			{
				i += 2;
				ret_format |= ANSI_FORMAT;
			}
		}
		else if((buf[i] & 0xF0) == 0xE0)//	1110xxxx 10xxxxxx 10xxxxxx
		{
			if((buf[i+1] & 0xC0) == 0x80 && (buf[i+2] & 0xC0) == 0x80)
			{
				i += 3;
				ret_format |= UTF_8_NOBOM_FORMAT;
			}
			else
			{
				i += 2;
				ret_format |= ANSI_FORMAT;
			}
		}
		else if((buf[i] & 0xF8) == 0xF0)//	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
		{
			if((buf[i+1] & 0xC0) == 0x80 && (buf[i+2] & 0xC0) == 0x80 && (buf[i+3] & 0xC0) == 0x80)
			{
				i += 4;
				ret_format |= UTF_8_NOBOM_FORMAT;
			}
			else
			{
				i += 2;
				ret_format |= ANSI_FORMAT;
			}
		}
		else if((buf[i] & 0xFC) == 0xF8)//	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
		{
			if((buf[i+1] & 0xC0) == 0x80 && (buf[i+2] & 0xC0) == 0x80 && (buf[i+3] & 0xC0) == 0x80 && (buf[i+4] & 0xC0) == 0x80)
			{
				i += 5;
				ret_format |= UTF_8_NOBOM_FORMAT;
			}
			else
			{
				i += 2;
				ret_format |= ASCII_FORMAT;
			}
		}
		else if((buf[i] & 0xFC) == 0xF8)//	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
		{
			if((buf[i+1] & 0xC0) == 0x80 && (buf[i+2] & 0xC0) == 0x80 && (buf[i+3] & 0xC0) == 0x80 && (buf[i+4] & 0xC0) == 0x80 && (buf[i+5] & 0xC0) == 0x80)
			{
				i += 6;
				ret_format |= UTF_8_NOBOM_FORMAT;
			}
			else
			{
				i += 2;
				ret_format |= ASCII_FORMAT;
			}
		}
		else
		{
			return ERROR_FORMAT;
		}
	}

	return ret_format;
}

int db_check_format(const uint8_t * buf, uint32_t len, int default_format)
{
	//	BOM							编码类型
	//	——————————————————————
	//	EF BB BF					UTF-8
	//	FE FF						UTF-16(大端)
	//	FF FE						UTF-16(小端)
	//	00 00 FE FF					UTF-32(大端)
	//	FF FE 00 00					UTF-32(小端)
	int ret_format = ASCII_FORMAT;
	if(len == 0)
	{
		return ERROR_FORMAT;
	}

	if(len >= 4)	//BOM判断
	{
		if(buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0xFE && buf[3] == 0xFF)
			return UTF_32_B_ENDIAN_FORMAT;
		if(buf[0] == 0xFF && buf[1] == 0xFE && buf[2] == 0x00 && buf[3] == 0x00)
			return UTF_32_L_ENDIAN_FORMAT;
		if(buf[0] == 0xFE && buf[1] == 0xFF)
			return UTF_16_B_ENDIAN_FORMAT;
		if(buf[0] == 0xFF && buf[1] == 0xFE)
			return UTF_16_L_ENDIAN_FORMAT;
		if(buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
			return UTF_8_BOM_FORMAT;
	}

#if (0)
	ret_format = db_check_format_no_bom(buf, len);
#else
	if(default_format == ANSI_FORMAT)
	{
		ret_format = is_gb2312_format(buf, len);
		if(ERROR_FORMAT == ret_format)
		{
			ret_format = is_utf8_format(buf, len);
		}
	}
	else
	{
		ret_format = is_utf8_format(buf, len);
		if(ERROR_FORMAT == ret_format)
		{
			ret_format = is_gb2312_format(buf, len);
		}
	}

#endif
	
	switch(ret_format)
	{
	case ASCII_FORMAT			:
	case ANSI_FORMAT			:
	case UTF_8_NOBOM_FORMAT		:
	case UTF_8_BOM_FORMAT		:
	case UTF_16_L_ENDIAN_FORMAT	:
	case UTF_16_B_ENDIAN_FORMAT	:
	case UTF_32_L_ENDIAN_FORMAT	:
	case UTF_32_B_ENDIAN_FORMAT	:
		return ret_format;

	case ERROR_FORMAT			:
		//既不是utf8，也不是GB2312，可能是日韩语，返回ANSI格式
		return ANSI_FORMAT;

	default						:
		return (UTF_8_NOBOM_FORMAT & ret_format);
	}
}
